function AEnigmatesStorage(puzzle) {
	if (!(this instanceof AEnigmatesStorage))
		return new AEnigmatesStorage(puzzle);

	if (!puzzle) {
		throw "Puzzle unique name must be provided as first parameter";
	}

	this.puzzle = puzzle;
}

AEnigmatesStorage.prototype.save = function(state) {
	$.jStorage.set(this.puzzle, state);
};

AEnigmatesStorage.prototype.update = function(state) {
	var updatedState = this.getState();

	if (state.solved != null) {
		updatedState.solved = state.solved;
	}
	if (state.unlocked != null) {
		updatedState.unlocked = state.unlocked;
	}

	$.jStorage.set(this.puzzle, updatedState);
};

AEnigmatesStorage.prototype.getState = function() {
	return $.jStorage.get(this.puzzle, AEnigmaState().undiscovered());
};

AEnigmatesStorage.prototype.solved = function() {
	this.save(AEnigmaState().solved());
};

AEnigmatesStorage.prototype.unlock = function() {
	this.update(AEnigmaState().unlocked());
};

AEnigmatesStorage.prototype.get = function(prop) {
	return this.getState()[prop];
};

AEnigmatesStorage.prototype.isSolved = function() {
	return this.get('solved');
};

AEnigmatesStorage.prototype.isUnlocked = function() {
	return this.get('unlocked');
};

AEnigmatesStorage.prototype.isUndiscovered = function() {
	return !this.isSolved() && !this.isUnlocked();
};

function AEnigmaState() {
	if (!(this instanceof AEnigmaState)) {
		return new AEnigmaState();
	}
}

AEnigmaState.prototype.solved = function() {
	return {
		solved : true,
		unlocked : true
	};
};

AEnigmaState.prototype.unlocked = function() {
	return {
		unlocked : true
	};
};

AEnigmaState.prototype.undiscovered = function() {
	return {
		solved : false,
		unlocked : false
	};
};
